package com.lollipop.synthential.algorithm;

import lombok.extern.slf4j.Slf4j;

import java.util.Random;

/**
 * @Author: J.K
 * @Date: 2022-07-29 14:34
 * @Description: 权重算法
 *
 * 先求和所有的权重值，再随机生成一个总权重之内的索引。
 * 遍历之前配置的服务器列表，用随机索引与每个节点的权重值进行判断。如果小于，则代表当前请求应该落入目前这个节点；如果大于，则代表随机索引超出了目前节点的权重范围，则减去当前权重，继续与其他节点判断。
 * 最终随机出的索引总会落入到一个节点的权重范围内，最后返回对应的节点 IP。
 */
@Slf4j
public class RandomWeightRibbon {
    public static String getServer() {
        Random random = new Random();
        
        // 计算总权重值
        int weightTotal = 0;
        for (Integer weight : WeightServers.WEIGHT_SERVERS.values()) {
            weightTotal += weight;
        }

        // 从总权重的范围内随机生成一个索引
        int index = random.nextInt(weightTotal);
        System.out.println(index);

        // 遍历整个权重集群的节点列表，选择节点处理请求
        String targetServer = "";
        for (String server : WeightServers.WEIGHT_SERVERS.keySet()) {
            // 获取每个节点的权重值
            Integer weight = WeightServers.WEIGHT_SERVERS.get(server);
            // 如果权重值大于产生的随机数，则代表此次随机分配应该落入该节点
            if (weight > index) {
                // 直接返回对应的节点去处理本次请求并终止循环
                targetServer = server;
                break;
            }
            // 如果当前节点的权重值小于随机索引，则用随机索引减去当前节点的权重值，
            // 继续循环权重列表，与其他的权重值进行对比，
            // 最终该请求总会落入到某个IP的权重值范围内
            index = index - weight;
        }
        // 返回选中的目标节点
        return targetServer;
    }

    public static void main(String[] args) {
        // 模拟10个客户端请求测试
        for (int i = 1; i <= 10; i++) {
            log.info("第[{}]个请求，服务节点：[{}]", i, RandomRibbon.getServer());
        }
    }
}
